package com.wecan.base.model;

import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.wecan.base.enums.ResultStatus;
import lombok.Data;
import org.apache.http.HttpStatus;

import java.io.Serializable;
import java.util.Date;

/**
 * @Author liuzhihao
 * @Date 2022.01.11
 * @Version 1.0.0
 * @Description 响应结果数据格式
 */
@Data
public class Result<T> implements Serializable {
    private int code = 0;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String msg;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String path;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private boolean success;

    private T data;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private int status;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date timestamp = new Date();

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Error error = new Error();

    public Result<T> path(String path) {
        this.path = path;
        return this;
    }

    public Result<T> type(ResultStatus resultStatus) {
        this.code = resultStatus.getCode();
        this.msg = resultStatus.getMessage();
        return this;
    }

    public Result<T> message(String message) {
        this.msg = message;
        return this;
    }

    public Result<T> status(int httpStatus) {
        this.status = httpStatus;
        return this;
    }

    public Result<T> data(T data) {
        this.data = data;
        return this;
    }

    public Result<T> code(int code) {
        this.code = code;
        return this;
    }

    public Result<T> stackTrace(StackTraceElement[] stackTrace) {
        this.error.setStackTrace(stackTrace);
        return this;
    }

    public Result<T> detail(String detail) {
        this.error.setDetail(detail);
        return this;
    }

    public Result<T> validation(String message, String code, String field) {
        this.error = new Error();
        this.error.setMsg(message);
        this.error.setCode(code);
        this.error.setField(field);
        return this;
    }

    private static <T> Result<T> create(String message, String detail, int code, int status, T data, StackTraceElement[] stackTrace) {
        Result<T> result = new Result<>();
        if (StringUtils.isNotBlank(message)) {
            result.message(message);
        }

        if (StringUtils.isNotBlank(detail)) {
            result.detail(detail);
        }

        result.code(code);
        result.status(status);
        result.data(data);

        if (ArrayUtils.isNotEmpty(stackTrace)) {
            result.stackTrace(stackTrace);
        } else {
            result.setError(null);
        }

        return result;
    }

    public static <T> Result<T> success(String message, int code, int status, T data) {
        Result result = create(message, null, code, status, data, null);
        result.setSuccess(true);
        return result;
    }

    public static <T> Result<T> success(String message, int code, T data) {
        return success(message, code, HttpStatus.SC_OK, data);
    }

    public static <T> Result<T> success(ResultStatus resultStatus, T data) {
        return success(resultStatus.getMessage(), resultStatus.getCode(), data);
    }

    public static <T> Result<T> success(String message, T data) {
        return success(message, ResultStatus.OK.getCode(), data);
    }

    public static <T> Result<T> success(String message) {
        return success(message, null);
    }

    public static <T> Result<T> success() {
        return success(ResultStatus.OK, null);
    }

    public static <T> Result<T> content(T data) {
        return success("操作成功！", data);
    }

    public static <T> Result<T> failure(String message, String detail, int code, int status, T data, StackTraceElement[] stackTrace) {
        Result result = create(message, detail, code, status, data, stackTrace);
        result.setSuccess(false);
        return result;
    }

    public static <T> Result<T> failure(String message, String detail, int code, int status, T data) {
        return failure(message, detail, code, status, data, null);
    }

    public static <T> Result<T> failure(String message, int code, int status, T data) {
        return failure(message, message, code, status, data);
    }

    public static <T> Result<T> failure(String message, String detail, int code, T data) {
        return failure(message, detail, code, HttpStatus.SC_INTERNAL_SERVER_ERROR, data);
    }

    public static <T> Result<T> failure(String message, int code, T data) {
        return failure(message, message, code, data);
    }

    public static <T> Result<T> failure(ResultStatus resultStatus, T data) {
        return failure(resultStatus.getMessage(), resultStatus.getCode(), data);
    }

    public static <T> Result<T> failure(String message, T data) {
        return failure(message, ResultStatus.FAIL.getCode(), data);
    }

    public static <T> Result<T> failure(String message) {
        return failure(message, null);
    }

    public static <T> Result<T> failure() {
        return failure(ResultStatus.FAIL, null);
    }

    public static <T> Result<T> empty(String message, int code) {
        Result result = create(message, null, code, HttpStatus.SC_NO_CONTENT, null, null);
        result.setSuccess(true);
        return result;
    }

    public static <T> Result<T> empty(ResultStatus resultStatus) {
        return empty(resultStatus.getMessage(), resultStatus.getCode());
    }

    public static <T> Result<T> empty(String message) {
        return empty(message, ResultStatus.NO_CONTENT.getCode());
    }

    public static <T> Result<T> empty() {
        return empty("未查询到相关内容！");
    }
}
